#include <arpa/inet.h>
#include <iostream>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>

class InetAddr
{
private:
    void N2Hport()
    {
        _port = ::ntohs(_udp.sin_port);
        // ntohs用于将网络字节顺序的端口号转换为主机字节顺序并赋值给 _port。
    }

    void N2Hip()
    {
        char _ipbuffer[64];
        const char *_outip =
            ::inet_ntop(AF_INET, &_udp.sin_addr, _ipbuffer, sizeof(_ipbuffer));
        if (_outip)
        {
            // 转换成功
            _ip = _outip;
        }
        else
        {
            _ip = "";
        }
    }

public:
    InetAddr()
    {
        _udp.sin_addr.s_addr = INADDR_ANY;
        _udp.sin_family = AF_INET;
        _udp.sin_port = 0;

        N2Hip();
        N2Hport();
    }

    InetAddr(const InetAddr &_inet)
    {
        _udp = _inet._udp;
        N2Hip();
        N2Hport();
    }

    InetAddr(uint16_t _outport)
    {
        _udp.sin_port = htons(_outport);
        _udp.sin_family = AF_INET;
        _udp.sin_addr.s_addr = INADDR_ANY;
        N2Hip();
        N2Hport();
    }

    InetAddr(const struct sockaddr_in &addr)
    {
        _udp = addr;

        N2Hip();
        N2Hport();
    }

    ~InetAddr()
    {
        // 没有动态分配内存 不需要调用析构函数
    }

    /*
  （1）返回Ip地址
  （2）获取端口号
  （3）获取网络地址长度 注意是网络地址就是专门的那种 不是主机内的Ip地址
  （4）获取网络地址 就是网络IPv4结构体的地址
    */

    struct sockaddr_in *IPv4UdpStructAddr() { return &_udp; }
    struct sockaddr *IPv4UdpStructAddrToCONV() { return (struct sockaddr *)&_udp; }
    socklen_t IPv4UdpStructLen() { return sizeof(_udp); }
    std::string HostIp() { return _ip; }
    uint16_t HostPort() { return _port; }

private:
    uint16_t _port;   // 端口号
    std::string _ip;  // IP地址
    sockaddr_in _udp; // 表示IPv4的结构体
};